<template>
  <el-dialog
    :close-on-click-modal="false"
    v-model="visible"
    title="链接"
    append-to-body
    align-center
    @close="resetForm"
    width="80%"
  >
    <el-row>
      <el-col :span="24">
        <el-form-item label="链接名称">
          <el-input v-model="joinName" style="width: 100%" placeholder="请输入链接名称" />
        </el-form-item>
      </el-col>
      <el-col :span="24">
        <el-form-item label="链接">
          <!-- <el-table :data="[]" border style="width: 100%">
            <el-table-column label="表名" align="center"></el-table-column>
            <el-table-column label="字段" align="center"></el-table-column>
            <el-table-column label="表名" align="center"></el-table-column>
            <el-table-column label="字段" align="center"></el-table-column>
          </el-table> -->
          <div style="width: 100%; display: flex; height: 100%">
            <div class="table-dnd" ref="dndContainerRef">
              <div
                class="dnd-item"
                v-for="(item, index) in joinNodes"
                :key="index"
                @mousedown="startDrag($event, item)"
              >
                <el-tooltip placement="top" :content="item.data.tableReName">
                  <div class="dnd-item-title">
                    {{ item.data.tableReName }}
                  </div>
                </el-tooltip>
              </div>
            </div>
            <div class="table-container" ref="refContainer"></div>
          </div>
        </el-form-item>
      </el-col>
      <el-col :span="24">
        <el-form-item label="字段">
          <el-table
            :data="tableList"
            ref="tableRef"
            border
            style="width: 100%"
            max-height="50vh"
            @selection-change="tableSelectChange"
          >
            <el-table-column type="selection" align="center" width="55" />
            <el-table-column label="表" prop="tableName" align="center" />
            <el-table-column label="字段" prop="reName" align="center" />
            <el-table-column label="注释" prop="COMMENTS" align="center">
              <template #default="scope">
                <span v-if="scope.row.FIELD_NAME">{{ scope.row.FIELD_NAME }}</span>
                <span v-else>{{ scope.row.COMMENTS }}</span>
              </template>
            </el-table-column>
            <el-table-column label="标签" prop="RANGE" align="center">
              <template #default="scope">
                <div v-if="scope.row.RANGE">
                  {{ scope.row.RANGE_VALUE || scope.row.RANGE }}
                </div>
                <span v-else>-</span>
              </template>
            </el-table-column>
            <el-table-column label="重命名" prop="joinReName" align="center">
              <template #default="{ row }">
                <el-input v-model="row.joinReName" placeholder="请输入重命名"></el-input>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
      </el-col>
      <el-col :span="24">
        <el-form-item label="筛选">
          <Condition ref="conditionRef" :fieldList="conditionList" />
        </el-form-item>
      </el-col>
    </el-row>
    <template #footer>
      <el-button @click="visible = false">取消</el-button>
      <el-button type="primary" :loading="submitBtnLoading" @click="handleCreate">确认</el-button>
    </template>
  </el-dialog>
  <el-dialog v-model="isShowJoinTypeDialog" title="选择链接类型" append-to-body width="30%">
    <div class="join-type">
      <div :class="['join-type-item', currentEdgeJoinType == 'inner' ? 'active' : '']" @click="joinTypeClick('inner')">
        <div class="join-type-img"><img src="../../../assets/image/innerJoin.png" alt="" /></div>
        <div class="join-type-info">
          <div class="join-type-name">inner join (内连接)</div>
          <div class="join-type-desc">从表L和表R中选择符合联接条件的所有记录。</div>
        </div>
      </div>
      <div :class="['join-type-item', currentEdgeJoinType == 'left' ? 'active' : '']" @click="joinTypeClick('left')">
        <div class="join-type-img"><img src="../../../assets/image/leftJoin.png" alt="" /></div>
        <div class="join-type-info">
          <div class="join-type-name">left join (左连接)</div>
          <div class="join-type-desc">选择表L中的所有记录，以及表R中符合联接条件的记录(如果有的话)。</div>
        </div>
      </div>
    </div>
    <template #footer>
      <el-button @click="isShowJoinTypeDialog = false">取消</el-button>
      <el-button type="primary" @click="joinTypeSubmit">确定</el-button>
    </template>
  </el-dialog>
</template>

<script setup>
import { Search, Flag } from '@element-plus/icons-vue'
import { Graph, Shape } from '@antv/x6'
import { Dnd } from '@antv/x6-plugin-dnd'
import { LINE_HEIGHT, erRectTemplate, erRectNode } from './join'
import Condition from './condition.vue'
import { nextTick, watch } from 'vue'
import { ElMessage } from 'element-plus'
const props = defineProps({
  id: {
    type: String,
    default: ''
  },
  visible: {
    type: Boolean,
    default: false
  },
  joinNodes: {
    type: Array,
    default: () => []
  },
  data: {
    type: Object,
    default: () => ({})
  }
})
const emit = defineEmits(['update:visible', 'create', 'update'])
const dndContainerRef = ref(null)
const graph = ref(null)
const dnd = ref(null)
const refContainer = ref(null)
const currentClickEdge = ref('')
const isShowJoinTypeDialog = ref(false)
const currentEdgeJoinType = ref('inner')
const tableList = ref([])
const choosedFields = ref([])
const tableRef = ref(null)
const conditionRef = ref(null)
const joinName = ref('')
const conditionList = ref([])
const resetForm = () => {
  emit('update:visible')
}
onMounted(() => {
  console.log(props.joinNodes)
  setTimeout(() => {
    Graph.registerPortLayout(
      'erPortPosition',
      (portsPositionArgs) => {
        return portsPositionArgs.map((_, index) => {
          return {
            position: {
              x: 0,
              y: (index + 1) * LINE_HEIGHT
            },
            angle: 0
          }
        })
      },
      true
    )
    Graph.registerNode('er-rect', erRectTemplate, true)
    graph.value = new Graph({
      container: refContainer.value,
      background: {
        color: '#F2F7FA'
      },
      panning: true,
      mousewheel: {
        enabled: true
      },
      grid: {
        size: 10, // 网格大小 10px
        visible: true // 绘制网格，默认绘制 dot 类型网格
      },
      connecting: {
        router: {
          name: 'er',
          args: {
            offset: 25,
            direction: 'H'
          }
        },
        createEdge(a) {
          console.log(a)
          return new Shape.Edge({
            attrs: {
              line: {
                sourceMarker: {
                  name: 'block'
                },
                targetMarker: {
                  name: 'block'
                },
                stroke: '#A2B1C3',
                strokeWidth: 2
              }
            }
          })
        }
      }
    })
    graph.value.on('edge:mouseenter', ({ cell }) => {
      if (cell.target.cell && !cell.target.port) {
        return
      }
      cell.addTools([
        {
          name: 'source-arrowhead'
        },
        {
          name: 'target-arrowhead',
          args: {
            attrs: {
              fill: 'red'
            }
          }
        }
      ])
    })

    graph.value.on('edge:mouseleave', ({ cell }) => {
      cell.removeTools()
    })
    graph.value.on('edge:connected', ({ isNew, edge }) => {
      if (isNew) {
        // 对新创建的边进行插入数据库等持久化操作
        console.log(true, edge)
        edgeLink(edge)
      } else {
        console.log(false, edge)
      }
    })
    graph.value.on('edge:click', ({ edge }) => {
      if (edge.target.cell && !edge.target.port) {
        console.log(edge)
        currentEdgeJoinType.value = edge.data.label
        currentClickEdge.value = edge
        isShowJoinTypeDialog.value = true
      }
    })
    dnd.value = new Dnd({
      target: graph.value,
      scaled: false,
      dndContainer: dndContainerRef.value,
      getDropNode(e) {
        console.log(e)
        const node = e.clone()
        return node
      }
    })
    console.log(props.data)
    if (props.data.joinName) {
      joinName.value = props.data.joinName
      const cells = []
      props.data.joinJSON.cells.forEach((item) => {
        if (item.shape === 'edge') {
          cells.push(graph.value.createEdge(item))
        } else {
          cells.push(graph.value.createNode(item))
        }
      })
      graph.value.resetCells(cells)
      // tableList.value = props.data.reNameFields
      // 接入的table有变化
      // 加了一个字段 或 减了一个字段 或 字段重命名修改
      // 以joinNodes为准  reNameFields覆盖
      // 暂时限制 只可加减字段，不可修改源，表，重命名
      console.log(props.joinNodes)
      // 链接
      props.joinNodes.forEach((item) => {
        graph.value.getNodes().forEach((i) => {
          if (item.id == i.data.originId) {
            console.log(item, i)
            console.log(i.getPorts())
            item.data.fieldList.forEach((k) => {
              const f = i.getPorts().find((i) => i.id == k.reName)
              if (!f) {
                i.addPort({
                  id: k.reName,
                  group: 'list',
                  attrs: {
                    portNameLabel: {
                      text: k.reName
                    },
                    portTypeLabel: {
                      text: k.DATA_TYPE || ''
                    },
                    portBody: {
                      stroke: '#5F95FF',
                      fill: '#EFF4FF'
                    }
                  }
                })
              }
            })
            i.getPorts().forEach((k) => {
              const f = item.data.fieldList.find((i) => i.reName == k.id)
              if (!f) {
                i.removePort(k.id)
              }
            })
          }
        })
      })
      // 字段
      tableList.value = []
      props.joinNodes.forEach((item, index) => {
        item.data.fieldList.forEach((i) => {
          tableList.value.push({
            ...i,
            tableName: item.data.tableReName,
            datasourceId: item.data.datasourceId,
            joinReName: i.reName
          })
        })
      })
      tableList.value.forEach((item) => {
        const f = props.data.reNameFields.find((i) => i.tableName == item.tableName && i.reName == item.reName)
        if (f) {
          item.joinReName = f.joinReName
        }
      })
      nextTick(() => {
        props.data.choosedFields.forEach((item) => {
          const field = tableList.value.find((i) => {
            return i.tableName == item.tableName && i.reName == item.reName && i.joinReName == item.joinReName
          })
          if (field) {
            tableRef.value.toggleRowSelection(field, true)
          }
        })
      })
      conditionRef.value.treeData = props.data.condition
    } else {
      console.log(props.joinNodes)
      props.joinNodes.forEach((item, index) => {
        if (index == 0) {
          joinName.value = item.data.tableReName
        } else {
          joinName.value += '-' + item.data.tableReName
        }
        item.data.fieldList.forEach((i) => {
          tableList.value.push({
            ...i,
            tableName: item.data.tableReName,
            datasourceId: item.data.datasourceId,
            joinReName: i.reName
          })
        })
      })
      console.log(tableList.value)
    }
    conditionList.value = tableList.value.map((item) => {
      return {
        ...item,
        COLUMN_NAME: item.tableName + '.' + item.reName
      }
    })
  }, 0)
})
const startDrag = (e, item) => {
  console.log(e, item)
  const node = graph.value.createNode(erRectNode)
  node.setAttrs({
    label: { text: item.data.tableReName }
  })
  node.setData({
    label: item.data.tableReName,
    originId: item.id,
    timeStamp: new Date().getTime()
  })
  const ports = []
  item.data.fieldList.forEach((i) => {
    ports.push({
      id: i.reName,
      group: 'list',
      attrs: {
        portNameLabel: {
          text: i.reName
        },
        portTypeLabel: {
          text: i.DATA_TYPE || ''
        },
        portBody: {
          stroke: '#5F95FF',
          fill: '#EFF4FF'
        }
      }
    })
  })
  node.addPorts(ports)
  dnd.value.start(node, e)
}
const edgeLink = (edge) => {
  const sourceNode = edge.getSourceNode()
  const targetNode = edge.getTargetNode()
  console.log(sourceNode, targetNode)
  // 判断先后顺序
  let turn = false
  if (sourceNode.data.timeStamp > targetNode.data.timeStamp) {
    turn = true
  }
  const linkEdge = graph.value.getEdges().filter((item) => {
    return item.source.cell == sourceNode.id && item.target.cell == targetNode.id
  })
  console.log(linkEdge)
  if (linkEdge.length == 1 && (!sourceNode.data.isJoin || !targetNode.data.isJoin)) {
    const edge = graph.value.addEdge({
      source: { cell: turn ? targetNode.id : sourceNode.id }, // 源节点和链接桩 ID
      target: { cell: turn ? sourceNode.id : targetNode.id }, // 目标节点 ID 和链接桩 ID
      label: getEdgeLabel('inner'),
      attrs: {
        line: {
          stroke: '#ffa940',
          strokeWidth: 2
        }
      }
    })
    edge.setData({
      label: 'inner',
      type: 'relation'
    })
    sourceNode.setData({
      isJoin: true
    })
    targetNode.setData({
      isJoin: true
    })
  }
}
const joinTypeClick = (type) => {
  currentEdgeJoinType.value = type
}
const joinTypeSubmit = () => {
  currentClickEdge.value.setLabels([getEdgeLabel(currentEdgeJoinType.value)])
  currentClickEdge.value.setData({
    label: currentEdgeJoinType.value
  })
  isShowJoinTypeDialog.value = false
}
const handleCreate = () => {
  if (choosedFields.value.length == 0) {
    ElMessage.warning('请选择字段')
    return
  }
  console.log(graph.value.toJSON())
  const joinRelation = graph.value.getEdges().filter((item) => item.data?.type == 'relation')
  const joinFields = graph.value.getEdges().filter((item) => item.data?.type != 'relation')
  console.log(props.joinNodes)
  const params = {
    joinName: joinName.value,
    joinJSON: graph.value.toJSON(),
    joinRelation: joinRelation.map((item) => {
      return {
        source: item.getSourceNode()?.data.label,
        target: item.getTargetNode()?.data.label,
        label: item.data.label
      }
    }),
    joinWhere: getJoinRelation(joinRelation),
    choosedFields: choosedFields.value,
    reNameFields: tableList.value,
    condition: conditionRef.value.treeData
  }
  console.log(params)
  emit('create', params)
  emit('update:visible', false)
}
const getJoinRelation = (relation) => {
  const nodes = graph.value.getNodes()
  console.log(nodes)
  const params = []
  // nodes的顺序和拖拽顺序一样
  nodes.forEach((item) => {
    // 查找链接的线
    const relationEdge = relation.find((i) => i.target.cell == item.id)
    const edges = graph.value
      .getEdges()
      .filter((i) => (i.source.cell == item.id || i.target.cell == item.id) && i.source.port && i.target.port)
    const data = {
      join: item.data.label,
      type: relationEdge?.data?.label || '',
      on: []
    }
    edges.forEach((i) => {
      // 判断线另一端节点与当前节点的先后顺序
      const sourceNode = i.getSourceNode()
      const targetNode = i.getTargetNode()
      let otherNode
      if (sourceNode.id == item.id) {
        otherNode = targetNode
      } else {
        otherNode = sourceNode
      }
      if (item.data.timeStamp > otherNode.data.timeStamp) {
        // 当前节点靠后，放在当前节点on后
        data.on.push({
          source: sourceNode.data.label,
          target: targetNode.data.label,
          sourceTable: i.source.port,
          targetTable: i.target.port
        })
      } else {
        // 当前节点考前，忽略
      }
    })
    params.push(data)
    // const relationEdge = relation.find((i) => i.source.cell == item.id)
    // if (relationEdge) {
    //   const targetNode = relationEdge.getTargetNode()
    //   const onList = field.filter((i) => i.source.cell == item.id && i.target.cell == targetNode.id)
    //   params.push({
    //     source: item.data.label,
    //     target: targetNode.data.label,
    //     join: relationEdge.data.label,
    //     on: onList.map((i) => {
    //       return {
    //         source: item.data.label,
    //         target: targetNode.data.label,
    //         sourceTable: i.source.port,
    //         targetTable: i.target.port
    //       }
    //     })
    //   })
    // }
  })
  return params
}
const tableSelectChange = (e) => {
  console.log(e)
  const fields = []
  for (let i = 0; i < e.length; i++) {
    if (fields.find((item) => item.joinReName == e[i].joinReName)) {
      ElMessage.warning('字段' + e[i].joinReName + '重复')
      tableRef.value.toggleRowSelection(e[i], false)
      return
    } else {
      fields.push(e[i])
    }
  }
  choosedFields.value = e.map((item) => {
    return {
      ...item,
      COLUMN_NAME_IN: item.COLUMN_NAME,
      COLUMN_NAME: item.joinReName
    }
  })
  // e.forEach((item) => {
  //   if (fields.find((i) => i == item.joinReName)) {
  //     ElMessage.warning('选择字段重命名不可重复')
  //   } else {
  //     fields.push(item.joinReName)
  //   }
  // })
}
// 工具   简化代码
const getEdgeLabel = (name) => {
  return {
    markup: [
      {
        tagName: 'rect',
        selector: 'labelBody'
      },
      {
        tagName: 'text',
        selector: 'labelText'
      }
    ],
    attrs: {
      labelText: {
        text: name,
        fill: '#ffa940',
        textAnchor: 'middle',
        textVerticalAnchor: 'middle'
      },
      labelBody: {
        ref: 'labelText',
        refX: -8,
        refY: -5,
        refWidth: '100%',
        refHeight: '100%',
        refWidth2: 16,
        refHeight2: 10,
        stroke: '#ffa940',
        fill: '#fff',
        strokeWidth: 2,
        rx: 5,
        ry: 5
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.table-dnd {
  width: 200px;
  height: calc(60vh - 2px);
  background-color: #f2f7fa;
  border: 1px solid #ccc;
  overflow: auto;
  margin-right: 10px;
  .dnd-item {
    width: 150px;
    height: 80px;
    background-color: #eff4ff;
    margin: 10px auto;
    color: #fff;
    border: 1px solid #5f95ff;
    cursor: move;
    .dnd-item-title {
      padding-left: 10px;
      border-bottom: 1px solid #fff;
      background-color: #5f95ff;
      line-height: 40px;
      font-size: 16px;
      font-weight: 700;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
}
.table-container {
  width: calc(100% - 210px);
  height: 60vh;
  border: 1px solid #ccc;
}
.join-type {
  width: 100%;
  .join-type-item {
    display: flex;
    padding: 10px 0;
    cursor: pointer;
    .join-type-img {
      img {
        height: 80px;
        width: 80px;
      }
    }
    .join-type-info {
      padding-left: 10px;
      .join-type-name {
        font-size: 18px;
        font-weight: 700;
      }
    }
  }
  .active {
    background-color: rgba(95, 149, 255, 0.2);
  }
}
</style>
